﻿using Autofac;
using Infrastructure;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Zj.HttpCodeDemo.Domain.Events;
using Zj.HttpCodeDemo.Mvc;

namespace Zj.HttpCodeDemo.Integration
{
    public class EventExcutionContext
        : IEventExcutionContext
    {
        private readonly ConcurrentDictionary<Type, List<Type>> _registrations;
        private readonly ContainerBuilder _builder= AutofacExt._builder;
        public EventExcutionContext()
        {
            this._registrations = new ConcurrentDictionary<Type, List<Type>>();
        }
        public async Task HandleEventAsync<TEvent>(TEvent @event) where TEvent : IEvent
        {
            var eventType = @event.GetType();
            if (this._registrations.TryGetValue(eventType, out List<Type> types))
            {
                if (types != null && types.Any())
                {
                    foreach (var type in types)
                    {
                        var container = this._builder.Build();
                        var handler = (IEventHandler)container.Resolve(type);
                        if (handler.CanHandle(@event))
                        {
                            await handler.HandleAsync(@event);
                        }
                    }
                }
            }
        }

        public void Registe<TEvent, TEventHandler>(TEvent @event, TEventHandler eventHandler)
            where TEvent : IEvent
            where TEventHandler : IEventHandler
        {
            var eventType = @event.GetType();
            var eventHandlerType = eventHandler.GetType();
            this.Registe(eventType, eventHandlerType);
        }


        public void Registe(Type eventType, Type eventHandlerType)
        {
            if (!HandlerRegistered(eventType, eventHandlerType))
            {
                Utils.ConcurrentDictionarySafeRegister(eventType, eventHandlerType, this._registrations);
                this._builder.RegisterType(eventHandlerType);
            }
        }

        public async Task RegisteAsync(Type eventType, Type eventHandlerType)
        {
            await Task.Run(() =>
            {
                this.Registe(eventType, eventHandlerType);
            }); 
        }

        public async Task RegistesAsync<TEvent, TEventHandler>(TEvent @event, TEventHandler eventHandler)
            where TEvent : IEvent
            where TEventHandler : IEventHandler
        {
            await Task.Run(() =>
            {
                this.Registe<TEvent, TEventHandler>(@event, eventHandler);
            });
        }

        public bool HandlerRegistered<TEvent, TEventHandler>(TEvent @event, TEventHandler eventHandler)
            where TEvent : IEvent
            where TEventHandler : IEventHandler
        {
            var eventType = @event.GetType();
            var eventHandlerType = eventHandler.GetType();
            return this.HandlerRegistered(eventType, eventHandlerType);
        }

        public bool HandlerRegistered(Type eventType, Type eventHandlerType)
        {
            if (this._registrations.TryGetValue(eventType, out List<Type> types))
            {
                return types != null && types.Any(t => t == eventHandlerType);
            }
            return false;
        }
    }
}
